#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>

//第12讲：深⼊理解指针(2)  第13讲：深⼊理解指针(3)
// 1. 数组名的理解
//数组名就是数组⾸元素(第⼀个元素)的地址
//int main()
//{
	//int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	//int* p = &arr[0];
	//printf("%zd\n", sizeof(p));//%zd是打印size_t类型的数据
	//printf("%zd\n", sizeof(arr));
	//既然数组名就是数组首元素的地址相当于arr=&arr[0],地址占8个字节（x64环境）,sizeof(arr)应该等于8才对呀?
	//原因在于:
	//sizeof(数组名)，sizeof中单独放数组名，这⾥的数组名表⽰整个数组，计算的是整个数组的⼤⼩，单位是字节
	//&数组名，这⾥的数组名表⽰整个数组，取出的是整个数组的地址（整个数组的地址和数组⾸元素的地址是有区别的）
	//除此之外，任何地⽅使⽤数组名，数组名都表⽰⾸元素的地址。
	
	//下面来看一个更直观的例子解释：数组的地址和数组中第一个元素地址是有区别的（仅仅只是值一样）
//	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };//arr的类型是int* 但是&arr的类型是?
//	printf("arr=\t\t%p\n", arr);//数组名就是首元素的地址，也就是指针类型:int*
//	printf("arr+1=\t\t%p\n", arr+1);//int*类型一次跳过四个字节
//
//	printf("&arr[0]=\t%p\n", &arr[0]);//同上
//	printf("&arr[0]+1=\t%p\n", &arr[0]+1);
//
//	printf("&arr=\t\t%p\n", &arr);//这是整个数组的地址
//	printf("&arr+1=\t\t%p\n", &arr+1);//跳过整个数组
//
//	return 0;
//}


//2. 使⽤指针访问数组
//为什莫能用指针去访问数组？
//1.数组中的元素在内存中是连续存放的
//2.通过指针+-整数的操作可以遍历数组中的每个元素
//arr[i]==*(arr+i) 这两种写法完全等价，在计算机内部实际上用*(arr+i)进行运算,arr[i]会被转换为*(arr+i)
//既然arr[i]==*(arr+i)，又因为*(arr+i)=*(i+arr),那么arr[i]是不是也可以写成i[arr]呢？答案是可以的(但是不推荐这种写法)
//因为两种写法都会被转换为:*(arr+i)或者*(i+arr)

//如果int*p=arr
//那么arr[i]也可以写作:p[i]


//3. ⼀维数组传参的本质
//数组传参的时候是可以写成数组的形式的，但是本质上传过去的还是指针变量:
//void test(int arr1[10])//形参和实参用的是同一个数组，传递的是首元素地址，[10]可以不用写,接收的类型可以直接写成: int*p
//{
//	int sz=sizeof(arr1)/sizeof(arr1[0]);//这里实际上是一个指针类型的大小除以一个int类型的大小,结果是2
//	printf("sz=%d", sz);
//}
//int main()
//{
//	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//	test(&arr);//这里传过去的是首元素的地址（其实就是指针变量,占8个字节(x64)）
//	return 0;
//}
//总结：⼀维数组传参，形参的部分可以写成数组的形式，也可以写成指针的形式。

//4. 冒泡排序
//冒泡排序的核⼼思想就是：两两相邻的元素进⾏⽐较
//正常写法:
//void Bubble(int arr[10], int sz)
//{
//	for (int i = 0; i < sz-1; i++, sz--)
//	{
//		for (int j = 0; j < sz - 1; j++)
//		{
//			if (arr[j] > arr[j + 1])
//			{
//				int temp = arr[j];
//				arr[j] = arr[j + 1];
//				arr[j + 1] = temp;
//			}
//		}
//	}
//}
//int main()
//{
//	int arr[10] = { 7,3,5,1,8,4,2,9,10,6 };
//	int sz = sizeof(arr) / sizeof(arr[0]);
//	Bubble(arr, sz);
//	for (int i = 0; i < sz; i++)
//	{
//		printf("%d ", arr[i]);
//	}
//	return 0;
//}

//优化:
//void Bubble(int arr[10], int sz)
//{
//	for (int i = 0; i < sz - 1; i++)
//	{
//		int flag = 1;//假设已经有序
//		for (int j = 0; j < sz-i- 1; j++)
//		{
//			if (arr[j] > arr[j + 1])
//			{
//				flag = 0;//无序
//				int temp = arr[j];
//				arr[j] = arr[j + 1];
//				arr[j + 1] = temp;
//			}
//		}
//		if (flag)
//		{
//			break;
//		}
//	}
//}
//int main()
//{
//	int arr[10] = { 7,3,5,1,8,4,2,9,10,6 };
//	int sz = sizeof(arr) / sizeof(arr[0]);
//	Bubble(arr, sz);
//	for (int i = 0; i < sz; i++)
//	{
//		printf("%d ", arr[i]);
//	}
//	return 0;
//}


//5. ⼆级指针
//指针变量也是变量，是变量就有地址，那指针变量的地址存放在哪⾥？
//这就是 ⼆级指针
//int main()
//{
//	int a = 10;
//	int* p = &a;  //*说明p是指针变量，int指的是p指向的是int类型的数据
//	int* * pp = &p;//*说明pp是指针变量，int*指的是pp指向的是int*类型的数据
//	printf("**pp=%d\n", **pp);
//	printf(" *pp=%p\n", *pp);
//	printf("   p=%p\n", p);
//	return 0;
//}



//6. 指针数组
//指针数组是指针还是数组？
//我们类⽐⼀下，整型数组，是存放整型的数组，字符数组是存放字符的数组。
//那指针数组呢？是存放指针的数组。
//指针数组的每个元素是地址，⼜可以指向⼀块区域。



//7. 指针数组模拟⼆维数组
//int main()
//{
//	int arr1[] = { 1,2,3,4,5 };
//	int arr2[] = { 2,3,4,5,6 };
//	int arr3[] = { 3,4,5,6,7 };
//
//	int* arr[] = { arr1,arr2,arr3 };
//	//打印数组:
//	int i = 0;
//	for (i = 0; i < 3; i++)
//	{
//		int j = 0;
//		for (j = 0; j < 5; j++)
//		{
//			printf("%d ", arr[i][j]);//先通过[i]找到数组名，再通过[j]找到该数组名中的元素
//		}							 //如果i=1，j=2，那就是:先找到arr2,然后再找到arr2[2]-->*(arr2+2)
//		printf("\n");				 //也就是: *(*(arr+1)+2) 本质是指针的运算
//	}
//	return 0;
//}

//第13讲：深⼊理解指针(3)
//1. 字符指针变量
//int main()
//{
	//char arr[10] = "abcdef";//字符数组
	//char* p1 = arr;//p1指向的是数组的首地址也就是a对应的地址.
	//char* p2 = "abcdef";//(常量字符串)p2指向a对应的地址.
	//printf("%s", p1);//当打印字符串的时候只需要首字符的地址就可以了，不需要解引用（如果解引用的话只能打印首字符）
	//这两种有什么区别呢？
	//字符数组里的内容可以改变，但是常量字符串里面的内容不可变
//	return 0;
//}

//写一道题:
//int main()
//{
//	char str1[] = "hello bit.";//数组在创建时会开辟一块空间，所以str1和str2的首地址不同
//	char str2[] = "hello bit.";
//	const char* str3 = "hello bit.";//相同的常量字符串，没必要保存两份，因为常量字符串不能被修改
//	const char* str4 = "hello bit.";//所以大家公用一份是能够满足的，这样也能节省空间，str3和str4都指向h对应的地址
//	if (str1 == str2)
//		printf("str1 and str2 are same\n");
//	else
//		printf("str1 and str2 are not same\n");
//
//	if (str3 == str4)
//		printf("str3 and str4 are same\n");
//	else
//		printf("str3 and str4 are not same\n");
//	return 0;
//}